Fixing UART DMA Issues on NVIDIA Jetpack 6.2.2
Introduction
This guide explains how to fix UART receive/transmit issues on NVIDIA Jetpack 6.2.2 platforms by forcing selected UART ports to run in PIO mode instead of DMA mode.
On affected JetPack 6 systems, some UART ports may receive corrupted data when the NVIDIA serial-tegra driver uses DMA. The workaround is to remove the dmas and dma-names properties from the relevant UART device-tree nodes using a device-tree overlay. When those properties are removed, the driver falls back to PIO mode.
This guide covers how to:
- Identify the UART device-tree nodes.
- Disable DMA for
serial@3100000andserial@3110000. - Compile the overlay into a
.dtbo. - Install the overlay using the JetsonHacks
jetson-orin-uartinstaller flow. - Verify that the UART ports are running in PIO mode after reboot.
What You Will Need
Before starting, make sure you have the following:
-
NVIDIA Jetson Orin device
Jetson Orin Nano, Orin NX. -
**JetPack 6.2.2 / L4T R36.5 This workaround is intended for JetPack 6 systems where the UART DMA issue appears.
-
Terminal access
Local terminal or SSH access to the Jetson. -
Root privileges
The installation modifies files under/boot, sosudois required. -
device-tree-compiler
Thedtctool is required to compile.dtsoverlays into.dtbofiles. -
JetsonHacks UART overlay repository
The guide assumes thejetson-orin-uartrepository is cloned on the Jetson.
Background: DMA Mode vs PIO Mode
Jetson UART ports are exposed through the Linux serial-tegra driver. Depending on the device-tree configuration, the driver may use DMA or PIO for UART data movement.
DMA Mode
In DMA mode, the UART driver uses the DMA engine to move UART data between hardware and memory. This reduces CPU involvement and is generally preferred for high-throughput serial traffic.
A UART node configured for DMA usually contains properties similar to:
dmas = <...>;
dma-names = "rx", "tx";
PIO Mode
PIO means Programmed I/O. In PIO mode, the CPU and UART driver move data through the UART registers directly, usually interrupt-driven.
The UART protocol, pins, baud rate, and Linux device name do not change. Only the internal data-transfer mechanism changes.
After the workaround is applied, the kernel log should show messages similar to:
serial-tegra 3100000.serial: RX in PIO mode
serial-tegra 3100000.serial: TX in PIO mode
serial-tegra 3110000.serial: RX in PIO mode
serial-tegra 3110000.serial: TX in PIO mode
Step 1: Clone the JetsonHacks UART Fix Repository
Clone the repository on the Jetson:
git clone https://github.com/jetsonhacks/jetson-orin-uart.git
cd jetson-orin-uart
The repository includes an install.sh script that:
- Compiles
disable-uart1-dma.dtsinto a device-tree overlay. - Copies the resulting
.dtbofile to/boot. - Detects the board FDT.
- Updates
/boot/extlinux/extlinux.conf. - Adds a new boot entry while keeping the previous entry as a fallback.
Step 2: Replace the DTS Overlay
Create or replace the overlay source file:
cat > disable-uart1-dma.dts <<'EOF'
/dts-v1/;
/plugin/;
/ {
overlay-name = "Disable UART DMA for 3100000 and 3110000";
fragment@0 {
target-path = "/bus@0/serial@3100000";
delete_prop = "dmas", "dma-names";
__overlay__ {
status = "okay";
};
};
fragment@1 {
target-path = "/bus@0/serial@3110000";
delete_prop = "dmas", "dma-names";
__overlay__ {
status = "okay";
};
};
};
EOF
This overlay removes the DMA properties from both UART nodes:
/bus@0/serial@3100000
/bus@0/serial@3110000
Removing dmas and dma-names causes the serial-tegra driver to fall back to PIO mode for those UARTs.
NOTE: The command above overwrites disable-uart1-dma.dts. If you want to keep the original file, back it up first:
cp disable-uart1-dma.dts disable-uart1-dma.dts.bak
Step 3: Install device-tree-compiler
Install dtc if it is not already available:
sudo apt update
sudo apt install -y device-tree-compiler
Verify that dtc is installed:
dtc --version
Step 4: Compile the Overlay Manually
Compile the .dts file into a .dtbo file:
dtc -@ -I dts -O dtb -o disable-uart1-dma.dtbo disable-uart1-dma.dts
Verify that the .dtbo was generated:
ls -l disable-uart1-dma.dtbo
You can also decompile it to inspect the result:
dtc -I dtb -O dts disable-uart1-dma.dtbo
Step 5: Run the Installer
Run the JetsonHacks install script:
sudo bash install.sh
The installer compiles the overlay again and installs it into:
/boot/disable-uart1-dma.dtbo
It also modifies:
/boot/extlinux/extlinux.conf
The installer creates a new boot entry named UARTFix and leaves the previous boot entry available as a fallback.
Step 6: Reboot
Reboot the Jetson:
sudo reboot
After reboot, the UARTFix boot entry should load the overlay.
Step 7: Verify PIO Mode
After the system comes back up, check the kernel log:
sudo dmesg | grep -iE '3100000|3110000|pio|dma|serial-tegra'
Look for lines similar to:
serial-tegra 3100000.serial: RX in PIO mode
serial-tegra 3100000.serial: TX in PIO mode
serial-tegra 3110000.serial: RX in PIO mode
serial-tegra 3110000.serial: TX in PIO mode
If those lines appear, the UART ports are running in PIO mode.
Step 8: Confirm the Overlay Was Added to extlinux.conf
Check the boot configuration:
grep -nA20 -B5 "UARTFix" /boot/extlinux/extlinux.conf
You should see an entry that references:
/boot/disable-uart1-dma.dtbo
You can also check for the overlay path directly:
grep -n "disable-uart1-dma.dtbo" /boot/extlinux/extlinux.conf
Step 9: Inspect the Running Device Tree
The running device tree is available under /proc/device-tree.
Check whether the UART nodes still expose DMA properties:
ls /proc/device-tree/bus@0/serial@3100000 | grep dma || true
ls /proc/device-tree/bus@0/serial@3110000 | grep dma || true
If the overlay was applied correctly, dmas and dma-names should not appear for those nodes.
You can also decompile the running device tree:
sudo dtc -I fs -O dts /proc/device-tree -o /tmp/running.dts
Then inspect the UART sections:
grep -nA30 "serial@3100000" /tmp/running.dts
grep -nA30 "serial@3110000" /tmp/running.dts
One-Step Patch, Compile, and Install Script
Instead of running the steps manually, you can use this wrapper script inside the cloned jetson-orin-uart directory.
Create the script:
cat > fix-uart-dma-and-install.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DTS="${REPO_DIR}/disable-uart1-dma.dts"
DTBO="${REPO_DIR}/disable-uart1-dma.dtbo"
INSTALL="${REPO_DIR}/install.sh"
if [[ "${EUID}" -ne 0 ]]; then
echo "[ERROR] Run this script with sudo:"
echo " sudo bash $0"
exit 1
fi
if [[ ! -f "${INSTALL}" ]]; then
echo "[ERROR] install.sh not found in ${REPO_DIR}"
echo " Run this script from inside the jetson-orin-uart repo."
exit 1
fi
if ! command -v dtc >/dev/null 2>&1; then
echo "[INFO] Installing device-tree-compiler..."
apt update
apt install -y device-tree-compiler
fi
if [[ -f "${DTS}" ]]; then
cp "${DTS}" "${DTS}.bak.$(date +%Y%m%d%H%M%S)"
echo "[INFO] Backed up existing DTS."
fi
cat > "${DTS}" <<'DTS_EOF'
/dts-v1/;
/plugin/;
/ {
overlay-name = "Disable UART DMA for 3100000 and 3110000";
fragment@0 {
target-path = "/bus@0/serial@3100000";
delete_prop = "dmas", "dma-names";
__overlay__ {
status = "okay";
};
};
fragment@1 {
target-path = "/bus@0/serial@3110000";
delete_prop = "dmas", "dma-names";
__overlay__ {
status = "okay";
};
};
};
DTS_EOF
echo "[INFO] Wrote patched DTS:"
echo " ${DTS}"
echo "[INFO] Compiling local DTBO for verification..."
dtc -@ -I dts -O dtb -o "${DTBO}" "${DTS}"
echo "[INFO] Decompile check:"
dtc -I dtb -O dts "${DTBO}" 2>/dev/null | grep -E 'serial@3100000|serial@3110000|delete_prop|dma-names|dmas' || true
echo "[INFO] Running original install.sh..."
bash "${INSTALL}"
echo
echo "[INFO] Done."
echo "[INFO] Reboot to apply:"
echo " sudo reboot"
echo
echo "[INFO] After reboot, check:"
echo " sudo dmesg | grep -iE '3100000|3110000|pio|dma|serial-tegra'"
EOF
Make it executable and run it:
chmod +x fix-uart-dma-and-install.sh
sudo bash ./fix-uart-dma-and-install.sh
Summary
You now have a device-tree overlay that disables UART DMA for:
/bus@0/serial@3100000
/bus@0/serial@3110000
The overlay removes:
dmas
dma-names
from those UART nodes. Without DMA properties, the serial-tegra driver falls back to PIO mode.
The expected result after reboot is:
serial-tegra 3100000.serial: RX in PIO mode
serial-tegra 3100000.serial: TX in PIO mode
serial-tegra 3110000.serial: RX in PIO mode
serial-tegra 3110000.serial: TX in PIO mode
This confirms that both UART nodes are no longer using DMA.